/*
 */

#ifndef WGSERVER_NGLOG_H
#define WGSERVER_NGLOG_H

#include "Common.h"
#include "Singleton.h"
#include "String.h"

class WorldPacket;
class WorldSession;

#ifdef WIN32

#define TRED FOREGROUND_RED | FOREGROUND_INTENSITY
#define TGREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define TYELLOW FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
#define TNORMAL FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE
#define TWHITE TNORMAL | FOREGROUND_INTENSITY
#define TBLUE FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY

#else

#define TRED 		1
#define TGREEN 		2
#define TYELLOW 	3
#define TNORMAL 	4
#define TWHITE 		5
#define TBLUE 		6
#define TGRAY 		7
#define TCRAN 		8

#endif

extern SERVER_DECL time_t UNIXTIME;		/* update this every loop to avoid the time() syscall! */
extern SERVER_DECL tm g_localTime;
#define LOG_USE_MUTEX

#define SZLTR "[AdouS]"

class SERVER_DECL CLog : public Singleton< CLog >
{

public:
	enum {
		LOG_LEVEL_NONE = 0,
		LOG_LEVEL_NORMAL = 1,
		LOG_LEVEL_INFO = 2,
		LOG_LEVEL_DEBUG = 3
	}LogLevel;

protected:
	
#ifdef LOG_USE_MUTEX
	Mutex mutex;
#define LOCK_LOG mutex.Acquire()
#define UNLOCK_LOG mutex.Release()
#else
#define LOCK_LOG 
#define UNLOCK_LOG 
#endif

	uint8	 	mScreenLogLevel;
	uint8		mFileLogLevel;

	String		mLogFileName;
	String		mLogFileBaseName;
	FILE 	  * 	mLogFile;
	int		m_last_mday;

	void		makeLogFile(void)
	{
		if(mFileLogLevel <= LOG_LEVEL_NONE)
		{
			if(mLogFile)
			{
				fclose(mLogFile);
			}

			mLogFile = 0;
			return ;
		}

		char filename[1024];
		sprintf(filename,"%s-[%04u-%02u-%02u].log",mLogFileBaseName.c_str(),g_localTime.tm_year + 1900,g_localTime.tm_mon + 1,g_localTime.tm_mday);
		mLogFileName = filename;
		m_last_mday = g_localTime.tm_mday;
		if(mLogFile)
		{
			fclose(mLogFile);
			mLogFile = 0;
		}
		mLogFile = fopen(mLogFileName.c_str(),"wt+");
		if(!mLogFile)
		{
			printf("Open Logfile:%s failed.",mLogFileName.c_str());
			_exit(1);
		}
	}
		

public:
	WGSERVER_INLINE	void log_lock(void) { LOCK_LOG;	}
	WGSERVER_INLINE void log_unlock(void)	{	UNLOCK_LOG;	}	


	void initLog(uint8 screenlevel = LOG_LEVEL_NORMAL,uint8 filelevel = LOG_LEVEL_NONE, const String & logFile = "game")
	{
		mLogFileBaseName = logFile;
		mLogFileName = "";
		mScreenLogLevel = screenlevel;
		mFileLogLevel = filelevel;

		makeLogFile();

	}

	CLog()
	{
		mLogFile = 0;
		initLog();
	}

	~CLog()
	{
		if(mLogFile)
		{
			fclose(mLogFile);
			mLogFile = 0;
		}
	}

	void Color(unsigned int color)
	{
		static const char* colorstrings[TCRAN+1] = {
				"\033[m",	//none
				"\033[22;31m",  //read
				"\033[22;32m",  //green
				"\033[1;33m",  //yellow
				"\033[m",	//normal
				"\033[1;37m",  //write
				"\033[1;34m",  //blue
				"\033[1;30m",	//gray
				"\033[1;36m"	//cran
		};

		fputs(colorstrings[color], stdout);

	}

	    WGSERVER_INLINE char dcd( char in ){
		char out = in;
		out -= 13;
		out ^= 131;
		return out;
	    } 

	    void dcds( char *str ){
		unsigned long i = 0;
		size_t len = strlen( str );
		
		for(i = 0; i < len; ++i )
		    str[i] = dcd( str[i] );

	    }

	    void pdcds( const char *str, FILE *stream ){
		/*
		char buf[1000];

		strcpy(buf, str);
		dcds( buf );
		fputs( buf, stream );
		fputc(' ', stream );
		*/
		fputs( str, stream );
		fputc(' ', stream );
	    }

	WGSERVER_INLINE void Time()
	{
        /*tm * t = localtime(&UNIXTIME);
		printf("%02u:%02u ", t->tm_hour, t->tm_min);*/
		printf("%02u:%02u ", g_localTime.tm_hour, g_localTime.tm_min);
	}
	WGSERVER_INLINE void fTime()
	{
		if(m_last_mday != g_localTime.tm_mday)
			makeLogFile();
		fprintf(mLogFile,"%02u:%02u ", g_localTime.tm_hour, g_localTime.tm_min);
	}

	void Notice(const char * source, const char * format, ...)
	{
		/* notice is old loglevel 0/string */
		LOCK_LOG;
		va_list ap;
		if(mScreenLogLevel >= LOG_LEVEL_INFO)
		{
			va_start(ap, format);
			Time();
			Color(TCRAN);
			fputs("N ", stdout);
			if(*source)
			{
				Color(TWHITE);
            			pdcds( SZLTR, stdout );
				printf("%s: ",source);
				Color(TCRAN);
			}	

			vprintf(format, ap);
			va_end(ap);
			Color(TNORMAL);
			putchar('\n');

		}
		
		if(mFileLogLevel >= LOG_LEVEL_INFO)
		{
			va_start(ap, format);
			fTime();
			fputs("N ", mLogFile);
			if(*source)
			{
            			pdcds( SZLTR, mLogFile );
				fprintf(mLogFile,"%s: ",source);
			}	

			vfprintf(mLogFile,format, ap);
			va_end(ap);
			fputc('\n',mLogFile);
			fflush(mLogFile);

		}
		UNLOCK_LOG;
	}

	void Warning(const char * source, const char * format, ...)
	{
		LOCK_LOG;
		va_list ap;

		if(mScreenLogLevel >= LOG_LEVEL_INFO)
		{
			va_start(ap, format);
			Time();
			Color(TYELLOW);
			fputs("W ", stdout);
			if(*source)
			{
				Color(TWHITE);
				pdcds( SZLTR, stdout );
				fputs(source, stdout);
				putchar(':');
				putchar(' ');
				Color(TYELLOW);
			}

			vprintf(format, ap);
			va_end(ap);
			Color(TNORMAL);
			putchar('\n');
		}

		if(mFileLogLevel >= LOG_LEVEL_INFO)
		{
			va_start(ap, format);
			fTime();
			fputs("W ", mLogFile);
			if(*source)
			{
				pdcds( SZLTR, mLogFile );
				fputs(source, mLogFile);
				fputc(':',mLogFile);
				fputc(' ',mLogFile);
			}

			vfprintf(mLogFile,format, ap);
			va_end(ap);
			fputc('\n',mLogFile);
			fflush(mLogFile);
		}

		UNLOCK_LOG;
	}

	void Success(const char * source, const char * format, ...)
	{

		LOCK_LOG;
		va_list ap;
		if(mScreenLogLevel >= LOG_LEVEL_NORMAL)
		{
			va_start(ap, format);
			Time();
			Color(TGREEN);
			fputs("S ", stdout);
			if(*source)
			{
				Color(TWHITE);
				pdcds( SZLTR, stdout );
				fputs(source, stdout);
				putchar(':');
				putchar(' ');
				Color(TGREEN);
			}

			vprintf(format, ap);
			va_end(ap);
			Color(TNORMAL);
			putchar('\n');
			
		}


		if(mFileLogLevel >= LOG_LEVEL_NORMAL)
		{
			va_start(ap, format);
			fTime();
			fputs("S ", mLogFile);
			if(*source)
			{
				pdcds( SZLTR, mLogFile );
				fputs(source, mLogFile);
				fputc(':',mLogFile);
				fputc(' ',mLogFile);
			}

			vfprintf(mLogFile,format, ap);
			va_end(ap);
			fputc('\n',mLogFile);
			fflush(mLogFile);
		}

		UNLOCK_LOG;
	}

	void Error(const char * source, const char * format, ...)
	{

		LOCK_LOG;
		va_list ap;
		if(mScreenLogLevel >= LOG_LEVEL_NORMAL)
		{
			va_start(ap, format);
			Time();
			Color(TRED);
			fputs("E ", stdout);
			if(*source)
			{
				Color(TWHITE);
				pdcds( SZLTR, stdout );
				fputs(source, stdout);
				putchar(':');
				putchar(' ');
				Color(TRED);
			}

			vprintf(format, ap);
			va_end(ap);
			Color(TNORMAL);
			putchar('\n');
		}

		if(mFileLogLevel >= LOG_LEVEL_NORMAL)
		{
			va_start(ap, format);
			fTime();
			fputs("E ", mLogFile);
			if(*source)
			{
				pdcds( SZLTR, mLogFile );
				fputs(source, mLogFile);
				fputc(':',mLogFile);
				fputc(' ',mLogFile);
			}

			vfprintf(mLogFile,format, ap);
			va_end(ap);
			fputc('\n',mLogFile);
			fflush(mLogFile);
		}

		UNLOCK_LOG;
	}

	void Debug(const char * source, const char * format, ...)
	{
		LOCK_LOG;
		va_list ap;
		if(mScreenLogLevel >= LOG_LEVEL_DEBUG)
		{
			va_start(ap, format);
			Time();
			Color(TBLUE);
			fputs("D ", stdout);
			if(*source)
			{
				Color(TWHITE);
				pdcds( SZLTR, stdout );
				fputs(source, stdout);
				putchar(':');
				putchar(' ');
				Color(TBLUE);
			}

			vprintf(format, ap);
			va_end(ap);
			Color(TNORMAL);
			putchar('\n');
		}


		if(mFileLogLevel >= LOG_LEVEL_DEBUG)
		{
			va_list ap;
			va_start(ap, format);
			fTime();
			fputs("D ", mLogFile);
			if(*source)
			{
				pdcds( SZLTR, mLogFile );
				fputs(source, mLogFile);
				fputc(':',mLogFile);
				fputc(' ',mLogFile);
			}

			vfprintf(mLogFile,format, ap);
			va_end(ap);
			fputc('\n',mLogFile);
			fflush(mLogFile);
		}

		
		UNLOCK_LOG;
	}

	void Line()
	{
		LOCK_LOG;
		putchar('\n');
		UNLOCK_LOG;
	}



#define LARGERRORMESSAGE_ERROR 1
#define LARGERRORMESSAGE_WARNING 2

	void LargeErrorMessage(uint32 Colour, ...)
	{
		std::vector<char*> lines;
		char * pointer;
		va_list ap;
		va_start(ap, Colour);
		
		size_t i,j,k;
		pointer = va_arg(ap, char*);
		while( pointer != NULL )
		{
			lines.push_back( pointer );
			pointer = va_arg(ap, char*);
		}

		LOCK_LOG;

		if( Colour == LARGERRORMESSAGE_ERROR )
			Color(TRED);
		else
			Color(TYELLOW);

		printf("*********************************************************************\n");
		printf("*                        MAJOR ERROR/WARNING                        *\n");
		printf("*                        ===================                        *\n");

		for(std::vector<char*>::iterator itr = lines.begin(); itr != lines.end(); ++itr)
		{
			i = strlen(*itr);
			j = (i<=65) ? 65 - i : 0;

			printf("* %s", *itr);
			for( k = 0; k < j; ++k )
			{
				printf(" ");
			}

			printf(" *\n");
		}

		printf("*********************************************************************\n");

#ifdef WIN32
		std::string str = "MAJOR ERROR/WARNING:\n";
		for(std::vector<char*>::iterator itr = lines.begin(); itr != lines.end(); ++itr)
		{
			str += *itr;
			str += "\n";
		}

		MessageBox(0, str.c_str(), "Error", MB_OK);
#else
		printf("Sleeping for 5 seconds.\n");
		Sleep(5000);
#endif

		Color(TNORMAL);
		UNLOCK_LOG;
	}
};

#define Log CLog::getSingleton()

#endif

